import { Bits } from "../util/Bits";
import { Cls } from "../util/Defined";
import { ECSCmp } from "./ECSCmp";
import { ECSEntity } from "./ECSEntity";
import { ECSFilter, IECSFilter, IECSFilterBits } from "./ECSFilter";
import { ECSMgr } from "./ECSMgr";

/**
 * [ECS]过滤器管理
 */
export class ECSFilterMgr extends ECSMgr {
	/** 相同key的filter */
	protected _filterMap = new Map<string, ECSFilter>();
	/** 关注对应组件类型的filter映射 */
	protected _watchCmpTypeFilterMap = new Map<Cls<ECSCmp>, Set<ECSFilter>>();
	/** 过滤器发生变化 */
	protected _filterDirty = false;

	/**
	 * 生成过滤器 相同参数的过滤器只会生成一个
	 * @param ifilter 过滤器参数
	 */
	genFilter(ifilter?: IECSFilter) {
		if (ifilter) {
			for (let key in ifilter) {
				if (!ifilter[key]?.length) {
					delete ifilter[key];
				}
			}

			//all里只有一个的都当作one
			if (!ifilter.includeOne && ifilter.includeAll?.length === 1) {
				ifilter.includeOne = ifilter.includeAll;
				delete ifilter.includeAll;
			}

			if (!ifilter.excludeOne && ifilter.excludeAll?.length === 1) {
				ifilter.excludeOne = ifilter.excludeAll;
				delete ifilter.excludeAll;
			}

			const filterBits: IECSFilterBits = {};
			const keys = Object.keys(ifilter).sort();
			const key = keys
				.map(key => {
					const filter = ifilter[key];
					const bits = new Bits();
					filter.forEach(cmpType => bits.setBit(this.scene.cmpMgr.getTypeIdx(cmpType), true));
					filterBits[key] = bits;
					return key + "_" + bits.toString(16);
				})
				.join("|");

			let filter = this._filterMap.get(key);
			if (!filter) {
				filter = new ECSFilter(filterBits);
				this._filterMap.set(key, filter);
				this._filterDirty = true;
				keys.forEach(key => {
					ifilter[key].forEach(cmpType => {
						let watches = this._watchCmpTypeFilterMap.get(cmpType);
						if (!watches) {
							watches = new Set();
							this._watchCmpTypeFilterMap.set(cmpType, watches);
						}
						watches.add(filter);
					});
				});
			}

			return filter;
		}
		return null;
	}

	/**
	 * 当实体添加/移除时通知过滤器
	 * @param entity 实体
	 */
	onEntityUpdate(entity: ECSEntity) {
		this._filterDirty = true;
		this._filterMap.forEach(filter => filter.onEntityUpdate(entity));
	}

	/**
	 * 当实体组件添加/移除时 通知关注该组件类型的filter更新
	 * @param entity 实体
	 * @param cmpType 组件类型
	 */
	onEntityCmpUpdate(entity: ECSEntity, cmpType: Cls<ECSCmp>) {
		const filters = this._watchCmpTypeFilterMap.get(cmpType);
		if (filters) {
			this._filterDirty = true;
			filters.forEach(filter => filter.onEntityUpdate(entity));
			if (!this.scene.inFrame) {
				//不在循环内立即更新
				this.update();
			}
		}
	}

	/**
	 * 当有组件变化时在同一时间里统一更新
	 */
	update() {
		if (this._filterDirty) {
			this._filterDirty = false;
			this._filterMap.forEach(this.updateFilter, this);
		}
	}

	private updateFilter(filter: ECSFilter) {
		filter.update();
	}

	protected onDestroy() {
		this._filterMap.forEach(filter => filter.destroy());
		this._filterMap.clear();
		this._watchCmpTypeFilterMap.clear();
	}
}
